package com.jasperframework.boot.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
  * <p> java压缩成zip </p>
  *
  * @site https://miliqkdoc.motopa.cn/
  * @author daizhao
  * @date 2018/11/22 14:56
  */
@Slf4j
public class ZipUtils {

    /**
     * 解压文件
     * @param fileName 解压文件的名称(绝对路径)
     * @param path     解压到指定路径
     */
    public static void unzip(String fileName, String path) {
        FileOutputStream fos = null;
        InputStream is = null;
        try {
            ZipFile zf = new ZipFile(new File(fileName), Charset.forName("GBK"));//设置编码 解决java.lang.IllegalArgumentException: MALFORMED
            Enumeration en = zf.entries();
            while (en.hasMoreElements()) {
                ZipEntry zn = (ZipEntry) en.nextElement();
                if (!zn.isDirectory()) {
                    is = zf.getInputStream(zn);
                    File f = new File(path + zn.getName());
                    File file = f.getParentFile();
                    file.mkdirs();
                    fos = new FileOutputStream(path + zn.getName());
                    int len;
                    byte[] buffer = new byte[is.available()];
                    while ((len = is.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                    }
                    fos.close();
                }
            }
            zf.close();
        } catch (ZipException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 递归压缩处理
     * @param file      待压缩的文件/文件夹
     * @param baseDir   父目录
     * @param zos       压缩文件输出流
     * @param deleteFlag   是否删除待压缩的文件/文件夹  true：删除  false：不删除
     */
    public static void zipFile(File file, String baseDir, ZipOutputStream zos, boolean deleteFlag) {
        InputStream is = null;
        try {
            if (!file.isDirectory()) {
                //定义输入文件流
                is = new FileInputStream(file);
                //实例化压缩输出流,并制定压缩文件的输出路径
                zos.putNextEntry(new ZipEntry(baseDir));
                //设置注释
                zos.setComment("////畅读阁下载txt////");
                byte[] buffer = new byte[is.available()];
                int bytesRead;
                while (-1 != (bytesRead = is.read(buffer, 0, buffer.length))) {
                    zos.write(buffer, 0, bytesRead);
                }
                zos.flush();
                zos.closeEntry();
            } else {
                String tempPath = null;
                for (File f : file.listFiles()) {
                    tempPath = baseDir + f.getName();
                    if(f.isDirectory()) {
                        tempPath += File.separator;
                    }
                    zipFile(f, tempPath, zos, deleteFlag);
                }
//                输出空文件夹
//                if(file.listFiles().length == 0){
//                    zos.putNextEntry(new ZipEntry(baseDir));
//                }
            }
        } catch (Exception e) {
            log.info("文件递归压缩处理异常={}", ExceptionUtil.getExceptionInfo(e));
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (deleteFlag) {
                    file.delete();
                }
            } catch (IOException e) {
                log.info("文件递归压缩收尾处理异常={}", ExceptionUtil.getExceptionInfo(e));
            }
        }

    }

    /**
     * <p> 压缩文件</p>
     *
     * @param fileName   待压缩文件（完整路径+文件名+后缀）
     * @param baseDir    待压缩的文件夹
     * @param zos        zip输出流
     * @param deleteFlag 压缩完成后是否删除 “待压缩文件”  true：删除，false：不删除，
     * @author youq  2018/11/22 14:57
     */
    public static void handleCompress(String fileName, String baseDir, ZipOutputStream zos, boolean deleteFlag) {
        InputStream is = null;
        //定义要压缩的文件
        File file = null;
        try {
            //定义要压缩的文件
            file = new File(fileName);
            //定义输入文件流
            is = new FileInputStream(file);
            //实例化压缩输出流,并制定压缩文件的输出路径
            zos.putNextEntry(new ZipEntry(StringUtils.isBlank(baseDir)
                    ? file.getName()
                    : baseDir + File.separator + file.getName()));
            //设置注释
            zos.setComment("////畅读阁下载txt////");
            byte[] buffer = new byte[is.available()];
            int bytesRead;
            while (-1 != (bytesRead = is.read(buffer, 0, buffer.length))) {
                zos.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            log.info("文件压缩处理异常={}", ExceptionUtil.getExceptionInfo(e));
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (deleteFlag) {
                    file.delete();
                }
            } catch (IOException e) {
                log.info("文件压缩收尾处理异常={}", ExceptionUtil.getExceptionInfo(e));
            }
        }

    }

    /**
     * <p> 压缩文件</p>
     * @param fileName 待压缩文件（完整路径+文件名+后缀）
     * @param zipFile  压缩文件的名称（完整路径+文件名+后缀）
     * @param deleteFlag 压缩完成后是否删除 “待压缩文件”  true：删除，false：不删除，
     */
    public static void handleCompress(String fileName, File zipFile, boolean deleteFlag) {
        InputStream is = null;
        //定义压缩输出流
        ZipOutputStream zipOut = null;
        //定义要压缩的文件
        File file = null;
        try {
            //定义要压缩的文件
            file = new File(fileName);
            //定义输入文件流
            is = new FileInputStream(file);
            //实例化压缩输出流,并制定压缩文件的输出路径
            zipOut = new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName("GBK"));//设置编码解决注释乱码
            zipOut.putNextEntry(new ZipEntry(file.getName()));
            //设置注释
            zipOut.setComment("////畅读阁下载txt////");
            byte[] buffer = new byte[is.available()];
            int bytesRead;
            while (-1 != (bytesRead = is.read(buffer, 0, buffer.length))) {
                zipOut.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            log.info("文件压缩处理异常={}", ExceptionUtil.getExceptionInfo(e));
        } finally {
            try {
                if(is != null){
                    is.close();
                }
                if(zipOut!=null){
                    zipOut.close();
                }
                if (deleteFlag) {
                    file.delete();
                }
            } catch (IOException e) {
                log.info("文件压缩收尾处理异常={}", ExceptionUtil.getExceptionInfo(e));
            }
        }

    }

    public static void testZipFile(){
        ZipOutputStream zos = null;
        try {
            zos = new ZipOutputStream(new FileOutputStream(new File("E:/test.zip")), Charset.forName("GBK"));
            zipFile(new File("E:/test"), "", zos, false);
        } catch (Exception ex) {
            ex.printStackTrace();
        }finally {
            try {
                if( zos != null){
                    zos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] temp) {
        //handleCompress("E:\\战神之踏上云巅.txt", "E:\\test.zip", false);
        testZipFile();
        unzip("E:\\test.zip", "D:/");
    }

}

